package ooo.reindeer.data.option;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import ooo.reindeer.data.annotation.*;
import ooo.reindeer.data.util.ByteDataUtil;
import ooo.reindeer.data.util.DataUtil;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@SuppressWarnings({"rawtypes"})
public class Coder<V, T> implements ICoder<V, T> {

    public final static Coder<Byte, Int8> INT8 = new Coder<Byte, Int8>() {
        @Override
        public Byte convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).byteValue();
            } else {
                return Byte.valueOf(value.toString());
            }
        }

        @Override
        public Byte deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                case LITTLE:
                default:
                    return buf.readByte();
            }

        }


        @Override
        public Byte deCode(ByteBuf buf, Int8 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                case LITTLE:
                default:
                    return buf.readByte();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Byte value, Endian endian) {
            switch (endian) {
                case BIG:
                case LITTLE:
                default:
                    buf.writeByte(value);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Byte value, Int8 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                case LITTLE:
                default:
                    buf.writeByte(value);
            }
        }
    };

    public final static Coder<Short, Int16> INT16 = new Coder<Short, Int16>() {

        @Override
        public Short convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).shortValue();
            } else {
                return Short.valueOf(value.toString());
            }
        }

        @Override
        public Short deCode(ByteBuf buf, Int16 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                    return buf.readShort();
                case LITTLE:
                default:
                    return buf.readShortLE();
            }

        }

        @Override
        public Short deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                    return buf.readShort();
                case LITTLE:
                default:
                    return buf.readShortLE();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Short value, Endian endian) {
            switch (endian) {
                case BIG:
                    buf.writeShort(value);
                    break;
                case LITTLE:
                default:
                    buf.writeShortLE(value);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Short value, Int16 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                    buf.writeShort(value);
                    break;
                case LITTLE:
                default:
                    buf.writeShortLE(value);
            }
        }
    };

    public final static Coder<Integer, Int32> INT32 = new Coder<Integer, Int32>() {

        @Override
        public Integer convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).intValue();
            } else {
                return Integer.valueOf(value.toString());
            }
        }

        @Override
        public Integer deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                    return buf.readInt();
                case LITTLE:
                default:
                    return buf.readIntLE();
            }

        }

        @Override
        public Integer deCode(ByteBuf buf, Int32 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                    return buf.readInt();

                case LITTLE:
                default:
                    return buf.readIntLE();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Integer value, Int32 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                    buf.writeInt(value);
                    break;
                case LITTLE:
                default:
                    buf.writeIntLE(value);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Integer value, Endian endian) {
            switch (endian) {
                case BIG:
                    buf.writeInt(value);
                    break;
                case LITTLE:
                default:
                    buf.writeIntLE(value);
            }
        }
    };

    public final static Coder<Long, Int64> INT64 = new Coder<Long, Int64>() {

        @Override
        public Long convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).longValue();
            } else {
                return Long.valueOf(value.toString());
            }
        }

        @Override
        public Long deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                    return buf.readLong();
                case LITTLE:
                default:
                    return buf.readLongLE();
            }

        }

        @Override
        public Long deCode(ByteBuf buf, Int64 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                    return buf.readLong();
                case LITTLE:
                default:
                    return buf.readLongLE();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Long value, Int64 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                    buf.writeLong(value);
                    break;
                case LITTLE:
                default:
                    buf.writeLongLE(value);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Long value, Endian endian) {
            switch (endian) {
                case BIG:
                    buf.writeLong(value);
                    break;
                case LITTLE:
                default:
                    buf.writeLongLE(value);
            }
        }
    };

    public final static Coder<Short, UnsignedInt8> UNSIGNED_INT8 = new Coder<Short, UnsignedInt8>() {

        @Override
        public Short convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).shortValue();
            } else {
                return Short.valueOf(value.toString());
            }
        }

        @Override
        public Short deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                case LITTLE:
                default:
                    return buf.readUnsignedByte();
            }

        }

        @Override
        public Short deCode(ByteBuf buf, UnsignedInt8 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                case LITTLE:
                default:
                    return buf.readUnsignedByte();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Short value, UnsignedInt8 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                case LITTLE:
                default:
                    buf.writeByte(value);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Short value, Endian endian) {
            switch (endian) {
                case BIG:
                case LITTLE:
                default:
                    buf.writeByte(value);
            }
        }
    };

    public final static Coder<Integer, UnsignedInt16> UNSIGNED_INT16 = new Coder<Integer, UnsignedInt16>() {

        @Override
        public Integer convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).intValue();
            } else {
                return Integer.valueOf(value.toString());
            }
        }

        @Override
        public Integer deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                    return buf.readUnsignedShort();
                case LITTLE:
                default:
                    return buf.readUnsignedShortLE();
            }

        }

        @Override
        public Integer deCode(ByteBuf buf, UnsignedInt16 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                    return buf.readUnsignedShort();
                case LITTLE:
                default:
                    return buf.readUnsignedShortLE();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Integer value, UnsignedInt16 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                    buf.writeShort(value);
                    break;
                case LITTLE:
                default:
                    buf.writeShortLE(value);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Integer value, Endian endian) {
            switch (endian) {
                case BIG:
                    buf.writeShort(value);
                    break;
                case LITTLE:
                default:
                    buf.writeShortLE(value);
            }
        }
    };

    public final static Coder<Long, UnsignedInt32> UNSIGNED_INT32 = new Coder<Long, UnsignedInt32>() {

        @Override
        public Long convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).longValue();
            } else {
                return Long.valueOf(value.toString());
            }
        }

        @Override
        public Long deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                    return buf.readUnsignedInt();
                case LITTLE:
                default:
                    return buf.readUnsignedIntLE();
            }

        }

        @Override
        public Long deCode(ByteBuf buf, UnsignedInt32 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                    return buf.readUnsignedInt();
                case LITTLE:
                default:
                    return buf.readUnsignedIntLE();
            }

        }

        @Override
        public void enCode(ByteBuf buf, Long value, UnsignedInt32 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                    buf.writeInt(value.intValue());
                    break;
                case LITTLE:
                default:
                    buf.writeIntLE(value.intValue());
            }
        }

        @Override
        public void enCode(ByteBuf buf, Long value, Endian endian) {
            switch (endian) {
                case BIG:
                    buf.writeInt(value.intValue());
                    break;
                case LITTLE:
                default:
                    buf.writeIntLE(value.intValue());
            }
        }
    };


    public final static Coder<BigInteger, UnsignedInt64> UNSIGNED_INT64 = new Coder<BigInteger, UnsignedInt64>() {

        @Override
        public BigInteger convert(Object value) {
            if (value instanceof Number) {
                return new BigInteger(Long.toUnsignedString(((Number) value).longValue()));
            } else {
                return new BigInteger(value.toString());
            }
        }

        @Override
        public BigInteger deCode(ByteBuf buf, Endian endian) {

            switch (endian) {
                case BIG:
                    return new BigInteger(Long.toUnsignedString(buf.readLong()));
                case LITTLE:
                default:
                    return new BigInteger(Long.toUnsignedString(buf.readLongLE()));
            }

        }

        @Override
        public BigInteger deCode(ByteBuf buf, UnsignedInt64 info, int length, Class clazz) {

            switch (info.value()) {
                case BIG:
                    return new BigInteger(Long.toUnsignedString(buf.readLong()));
                case LITTLE:
                default:
                    return new BigInteger(Long.toUnsignedString(buf.readLongLE()));
            }

        }

        @Override
        public void enCode(ByteBuf buf, BigInteger value, UnsignedInt64 info, Class clazz) {
            switch (info.value()) {
                case BIG:
                    buf.writeLong(value.longValue());
                    break;
                case LITTLE:
                default:
                    buf.writeLongLE(value.longValue());
            }
        }

        @Override
        public void enCode(ByteBuf buf, BigInteger value, Endian endian) {
            switch (endian) {
                case BIG:
                    buf.writeLong(value.longValue());
                    break;
                case LITTLE:
                default:
                    buf.writeLongLE(value.longValue());
            }
        }
    };

    public final static Coder<String, OCTString> OCT_STRING = new Coder<String, OCTString>() {

        @Override
        public String convert(Object value) {
            return value.toString();
        }

        @Override
        public String deCode(ByteBuf buf, OCTString info, int length, Class clazz) {

            byte[] octBytes = new byte[info.value()];

            buf.readBytes(octBytes);

            switch (info.align()) {
                case RIGHT:
                    int startIndex = -1;
                    for (int i = 0; i < octBytes.length; i++) {
                        if (octBytes[i] != info.padding()) {
                            startIndex = i;
                            break;
                        }
                    }
                    try {
                        return new String(octBytes, startIndex, octBytes.length - startIndex, info.charSet());
                    } catch (UnsupportedEncodingException e) {
                        throw new RuntimeException(e);
                    }

                case LEFT:
                default:
                    int endIndex = -1;
                    for (int i = octBytes.length - 1; i >= 0; i--) {
                        if (octBytes[i] != info.padding()) {
                            endIndex = i;
                            break;
                        }
                    }
                    try {
                        return new String(octBytes, 0, endIndex + 1, info.charSet());
                    } catch (UnsupportedEncodingException e) {
                        throw new RuntimeException(e);
                    }
            }
        }

        @Override
        public void enCode(ByteBuf buf, String value, OCTString info, Class clazz) {

            byte[] octBytes = new byte[info.value()];
            Arrays.fill(octBytes, info.padding());
            try {
                byte[] strBytes = value.getBytes(info.charSet());
                //noinspection DuplicatedCode
                switch (info.align()) {
                    case RIGHT:
                        System.arraycopy(strBytes, 0, octBytes, octBytes.length - strBytes.length, strBytes.length);
                        break;
                    case LEFT:
                    default:
                        System.arraycopy(strBytes, 0, octBytes, 0, strBytes.length);
                }
                buf.writeBytes(octBytes);

            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }

        }
    };

    public final static Coder<byte[], OCTBytes> OCT_BYTES = new Coder<byte[], OCTBytes>() {

        @Override
        public byte[] convert(Object value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public byte[] deCode(ByteBuf buf, OCTBytes info, int length, Class clazz) {

            byte[] octBytes = new byte[info.value()];

            buf.readBytes(octBytes);

            switch (info.align()) {
                case RIGHT:
                    int startIndex = -1;
                    for (int i = 0; i < octBytes.length; i++) {
                        if (octBytes[i] != info.padding()) {
                            startIndex = i;
                            break;
                        }
                    }
                    return Arrays.copyOfRange(octBytes, startIndex, octBytes.length - startIndex);
                case LEFT:
                default:
                    int endIndex = -1;
                    for (int i = octBytes.length - 1; i >= 0; i--) {
                        if (octBytes[i] != info.padding()) {
                            endIndex = i;
                            break;
                        }
                    }
                    return Arrays.copyOfRange(octBytes, 0, endIndex + 1);
            }
        }

        @Override
        public void enCode(ByteBuf buf, byte[] value, OCTBytes info, Class clazz) {

            byte[] octBytes = new byte[info.value()];
            Arrays.fill(octBytes, info.padding());

            //noinspection DuplicatedCode
            switch (info.align()) {
                case RIGHT:
                    System.arraycopy(value, 0, octBytes, octBytes.length - value.length, value.length);
                    break;
                case LEFT:
                default:
                    System.arraycopy(value, 0, octBytes, 0, value.length);
            }
            buf.writeBytes(octBytes);

        }
    };

    public final static Coder<byte[], BaseBytes> BASE_BYTES = new Coder<byte[], BaseBytes>() {

        @Override
        public byte[] convert(Object value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public byte[] deCode(ByteBuf buf, BaseBytes info, int length, Class clazz) {

            if (length == Type.AUTO_LENGTH) {
                throw new RuntimeException("base bytes  is not supported Auto length");
            }

            byte[] octBytes = new byte[length];

            buf.readBytes(octBytes);

            return octBytes;

        }

        @Override
        public void enCode(ByteBuf buf, byte[] value, BaseBytes info, Class clazz) {
            buf.writeBytes(value);
        }
    };

    public final static Coder<String, BaseString> BASE_STRING = new Coder<String, BaseString>() {

        @Override
        public String convert(Object value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public String deCode(ByteBuf buf, BaseString info, int length, Class clazz) {

            if (length == Type.AUTO_LENGTH) {
                throw new RuntimeException("base string  is not supported Auto length");
            }

            byte[] octBytes = new byte[length];

            buf.readBytes(octBytes);

            try {
                return new String(octBytes, info.charSet());
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void enCode(ByteBuf buf, String value, BaseString info, Class clazz) {
            try {
                buf.writeBytes(value.getBytes(info.charSet()));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    };

    public final static Coder<String, DynamicString> DYNAMIC_STRING = new Coder<String, DynamicString>() {

        @Override
        public String convert(Object value) {
            return value.toString();
        }

        @Override
        public String deCode(ByteBuf buf, DynamicString info, int length, Class clazz) {
            byte[] bytes;
            if (info.startMark().length != 0 && info.endMark().length != 0) {

                bytes = ByteDataUtil.readMarkBytes(buf, info.startMark(), info.startMark());

            } else {
                Object value = info.lengthFieldType().coder().deCode(buf, info.endian());
                length = (Integer) DataUtil.convert(Integer.class, value);

                bytes = new byte[length];
                buf.readBytes(bytes);
            }

            try {
                return new String(bytes, info.charSet());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }

        @Override
        public void enCode(ByteBuf buf, String value, DynamicString info, Class clazz) {

            byte[] valueBytes;
            try {
                valueBytes = value.getBytes(info.charSet());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            //noinspection DuplicatedCode
            if (info.startMark().length != 0 && info.endMark().length != 0) {
                buf.writeBytes(info.startMark());
                buf.writeBytes(valueBytes);
                buf.writeBytes(info.endMark());
            } else {
                Coder coder = info.lengthFieldType().coder();
                //noinspection unchecked
                coder.enCode(buf, coder.convert(valueBytes.length), info.endian());
                buf.writeBytes(valueBytes);
            }
        }
    };

    public final static Coder<byte[], DynamicBytes> DYNAMIC_BYTES = new Coder<byte[], DynamicBytes>() {
        @Override
        public byte[] convert(Object value) {
            return (byte[]) value;
        }

        @Override
        public byte[] deCode(ByteBuf buf, DynamicBytes info, int length, Class clazz) {
            byte[] bytes;

            if (info.startMark().length != 0 && info.endMark().length != 0) {

                bytes = ByteDataUtil.readMarkBytes(buf, info.startMark(), info.startMark());

            } else {
                bytes = new byte[(Integer) DataUtil.convert(Integer.class, info.lengthFieldType().coder().deCode(buf, info.endian()))];
                buf.readBytes(bytes);
            }

            return bytes;

        }

        @Override
        public void enCode(ByteBuf buf, byte[] value, DynamicBytes info, Class clazz) {

            byte[] valueBytes;
            try {
                valueBytes = value;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            //noinspection DuplicatedCode
            if (info.startMark().length != 0 && info.endMark().length != 0) {
                buf.writeBytes(info.startMark());
                buf.writeBytes(valueBytes);
                buf.writeBytes(info.endMark());
            } else {
                Coder coder = info.lengthFieldType().coder();
                //noinspection unchecked
                coder.enCode(buf, coder.convert(valueBytes.length), info.endian());
                buf.writeBytes(valueBytes);
            }
        }
    };
    public final static Coder<Object, Struct> STRUCT = new Coder<Object, Struct>() {

        @Override
        public Object convert(Object value) {
            return value;
        }

        @Override
        public Object deCode(ByteBuf buf, Struct info, int length, Class clazz) {
            try {

                if (info.clazz() == Object.class) {
                    //noinspection unchecked
                    return ByteDataUtil.toObject(buf, clazz);
                } else {
                    //noinspection unchecked
                    return ByteDataUtil.toObject(buf, info.clazz());
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void enCode(ByteBuf buf, Object value, Struct info, Class clazz) {
            try {
                ByteDataUtil.toBytesEx(buf, value);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    };

    public final static Coder<Object, Stream> STREAM = new Coder<Object, Stream>() {

        private final Map<String,Field> fields = new ConcurrentHashMap<>();

        @Override
        public Object convert(Object value) {
            return value;
        }

        @Override
        public Object deCode(ByteBuf buf, Stream info, int length, Class clazz) {
            try {

                if (clazz.isArray()) {

                    ArrayList<Object> list = new ArrayList<>();

                    while (buf.readableBytes() > 0) {
                        //noinspection unchecked
                        list.add(ByteDataUtil.toObject(buf, info.clazz()));
                    }
                    Object arrayRef = Array.newInstance(info.clazz(), list.size());

                    for (int i = 0; i < list.size(); i++) {
                        Array.set(arrayRef, i, list.get(i));
                    }

                    return arrayRef;
                } else if (Collection.class.isAssignableFrom(clazz)) {


                    Object o = newInstanceDefault(clazz);
                    if (o instanceof List) {
                        List list = (List) o;
                        while (buf.readableBytes() > 0) {
                            //noinspection unchecked
                            list.add(ByteDataUtil.toObject(buf, info.clazz()));
                        }
                    }
                    return o;
                } else if (Map.class.isAssignableFrom(clazz)) {
                    Map<Object, Object> map = new HashMap<>();
                    String cacheKey = info.clazz().getName() + ":" + info.keyFieldName();
                    Field field =fields.get(cacheKey);

                    if (field==null) {
                        synchronized (fields){
                            field =fields.get(cacheKey);
                            if (field==null){
                                field = info.clazz().getDeclaredField(info.keyFieldName());
                                field.setAccessible(true);
                                fields.put(cacheKey,field);
                            }
                        }
                    }

                    while (buf.readableBytes() > 0) {
                        //noinspection unchecked
                        Object object = ByteDataUtil.toObject(buf, info.clazz());
                        field.setAccessible(true);
                        Object key = field.get(object);
                        map.put(key, object);
                    }
                    return map;
                } else {
                    //noinspection unchecked
                    return ByteDataUtil.toObject(buf, clazz);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        private Object newInstanceDefault(Class clazz) throws Exception {
            if (clazz.isInterface()) {
                if (clazz.equals(List.class) || clazz.equals(Iterable.class) || clazz.equals(Collection.class)) {
                    return new ArrayList();
                } else if (clazz.equals(Set.class)) {
                    return new HashSet();
                } else if (clazz.equals(Map.class)) {
                    return new HashMap();
                } else {
                    return clazz.newInstance();
                }
            } else {
                return clazz.newInstance();
            }
        }

        @Override
        public void enCode(ByteBuf buf, Object value, Stream info, Class clazz) {
            try {
                if (value == null) {
                    return;
                }

                Class valueClass = value.getClass();


                if (valueClass.isArray()) {


                    Object[] objectArr = (Object[]) value;
                    for (Object object : objectArr) {
                        ByteDataUtil.toBytes(buf, object);
                    }


                } else if (Iterable.class.isAssignableFrom(valueClass)) {
                    Iterable iterable = (Iterable) value;

                    for (Object object : iterable) {
                        ByteDataUtil.toBytes(buf, object);
                    }

                } else if (Map.class.isAssignableFrom(valueClass)) {
                    Map map = (Map) value;
                    for (Object object : map.values()) {
                        ByteDataUtil.toBytes(buf, object);
                    }
                } else {
                    ByteDataUtil.toBytes(buf, value);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    };


    public final static Coder<Long, UnsignedIntVar> UNSIGNED_INT_VAR = new Coder<Long, UnsignedIntVar>() {


        @Override
        public Long convert(Object value) {
            if (value instanceof Number) {
                return ((Number) value).longValue();
            } else {
                return Long.valueOf(value.toString());
            }
        }

        /**
         * 编码使用uint var
         *
         * @param buf
         *         缓冲区
         * @param value
         *         值
         */
        private void encodeUintVar(ByteBuf buf, long value) {
            if (value < 0) {
                throw new IllegalArgumentException("value must be positive");
            }
            if (value < 0x80) {
                buf.writeByte((int) value);
            } else if (value < 0x4000) {
                buf.writeByte((int) (value | 0x80));
                buf.writeByte((int) (value >>> 7)&0x7f);
            } else if (value < 0x200000) {
                buf.writeByte((int) (value | 0x80));
                buf.writeByte((int) (value >>> 7)| 0x80);
                buf.writeByte((int) (value >>> 14)&0x7f);
            } else if (value < 0x10000000) {
                buf.writeByte((int) (value | 0x80));
                buf.writeByte((int) (value >>> 7)| 0x80);
                buf.writeByte((int) (value >>> 14)| 0x80);
                buf.writeByte((int) (value >>> 21)&0x7f);
            } else {
                buf.writeByte((int) (value | 0x80));
                buf.writeByte((int) (value >>> 7)| 0x80);
                buf.writeByte((int) (value >>> 14)| 0x80);
                buf.writeByte((int) (value >>> 21)| 0x80);
                buf.writeByte((int) (value >>> 28)&0x7f);
            }
        }

        /**
         * 获得变长整形长度大小
         *
         * @param value
         *         值
         *
         * @return int
         */


        /**
         * 解码使用uint var
         *
         * @param buf
         *         缓冲区
         *
         * @return long
         */
        private long decodeUintVar(ByteBuf buf) {
            int b = buf.readUnsignedByte();
            if ((b & 0x80) == 0) {
                return b;
            }
            long result = b & 0x7F;
            int shift = 7;
            while ((b & 0x80) != 0) {
                b = buf.readUnsignedByte();
                result |= (long) (b & 0x7F) << shift;
                shift += 7;
            }
            return result;
        }

        @Override
        public Long deCode(ByteBuf buf, UnsignedIntVar info, int length, Class clazz) {
            return decodeUintVar(buf);
        }

        @Override
        public void enCode(ByteBuf buf, Long value, UnsignedIntVar info, Class clazz) {

            encodeUintVar(buf, value);

        }



        @Override
        public Long deCode(ByteBuf buf, Endian endian) {
            return deCode(buf, null,1, Long.class);
        }

        @Override
        public void enCode(ByteBuf buf, Long value, Endian endian) {
            enCode(buf, value, null, Long.class);
        }
    };

    @Override
    public V convert(Object value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public V deCode(ByteBuf buf, Endian endian) {
        throw new UnsupportedOperationException();
    }

    @Override
    public V deCode(ByteBuf buf, T info, int length, Class clazz) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void enCode(ByteBuf buf, V value, T info, Class clazz) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void enCode(ByteBuf buf, V value, Endian endian) {
        throw new UnsupportedOperationException();
    }

}
